﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.EntityFrameworkCore;
using WorkFlowCore.Authorization;
using WorkFlowCore.Framework.MultipleApp;
using WorkFlowCore.IRepositories;
using WorkFlowCore.WorkTasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace WorkFlowCore.Framework.Repositories4EF
{
    public class WorkTaskRepository4EF : BasicRepository4EF<WorkTaskInfo, Guid>, IWorkTaskRepository
    {
        private readonly IWorkflowSession session;
        private readonly WorkflowDbContext workflowDbContext;
        private readonly IWorkStepRepository workStepRepository;

        public WorkTaskRepository4EF(IWorkflowSession session, WorkflowDbContext workflowDbContext, IDbContextProvider<WorkflowDbContext> dbContextProvider, IWorkStepRepository workStepRepository) 
            : base(session,dbContextProvider)
        {
            this.session = session;
            this.workflowDbContext = workflowDbContext;
            this.workStepRepository = workStepRepository;
        }

        public async Task<PageResult<StepWorkTask>> GetAllTasksOfUserAsync(string userId, int pageIndex = 1, int pageSize = -1)
        {
            var workStepInfos = workflowDbContext.Set<WorkStepInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(ws => ws.HandleUser_Id == userId);

            var workTaskInfos = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt => !wt.IsSimulation);


            return await GetResultAsync(workStepInfos, workTaskInfos, pageIndex, pageSize);
        }

        public async Task<PageResult<StepWorkTask>> GetHandledWorkTasksOfUserAsync(string userId, int pageIndex = 1, int pageSize = -1)
        {
            var workStepInfos = workflowDbContext.Set<WorkStepInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(ws => ws.HandleUser_Id == userId && (ws.WorkStepType == WorkStepType.ReadOnly || ws.IsHandled && ws.HandleType != WorkStepHandleType.UnWork ));

            var workTaskInfos = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt =>!wt.IsSimulation &&wt.CreatedUserId!= userId);

            return await GetResultAsync(workStepInfos, workTaskInfos, pageIndex, pageSize);
        }

        public async Task<PageResult<WorkTask>> GetTasksOfStartUserAsync(string userId, int pageIndex = 1, int pageSize = -1)
        {
            var result = new PageResult<WorkTask>
            {
                Total = (await GetCountAsync(wt => wt.ModifiedUserId == userId))
            };
            var worktaskQuery = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt => wt.ModifiedUserId == userId);

            if (pageSize < 1)
                result.Items = worktaskQuery.Select(ws=>ws.ToWorkTask()).ToList();
            else result.Items = worktaskQuery.OrderByDescending(w => w.CreationTime).Skip((pageIndex - 1) * pageSize).Take( pageSize).Select(w => w.ToWorkTask()).ToList();
            return await Task.FromResult(result);
        }

        public async Task<PageResult<StepWorkTask>> GetUnHandledWorkTasksOfUserAsync(string userId, int pageIndex = 1, int pageSize = -1)
        {
            var workStepInfos = workflowDbContext.Set<WorkStepInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(ws => ws.HandleUser_Id == userId && !ws.IsHandled); 

            var workTaskInfos = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt =>!wt.IsSimulation);

            return await GetResultAsync(workStepInfos, workTaskInfos, pageIndex, pageSize);
        }

        public async Task<PageResult<WorkTask>> GetWorkTasksOfCreatorAsync(string userId, int pageIndex = 1, int pageSize = -1)
        {
            var worktaskQuery = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt => !wt.Deleted && wt.CreatedUserId == userId && !wt.IsSimulation);
            var result = new PageResult<WorkTask>
            {
                Total = worktaskQuery.Count()
            };
            if (pageSize < 1)
                result.Items = worktaskQuery.Select(w => w.ToWorkTask()).ToList();
            else result.Items = worktaskQuery.OrderByDescending(w => w.CreationTime).Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(w => w.ToWorkTask()).ToList();
            return await Task.FromResult(result);
        }

        public async Task<PageResult<WorkTask>> GetAllWorkTasksAsync(int pageIndex = 1, int pageSize = -1)
        {
            var worktaskQuery = workflowDbContext.Set<WorkTaskInfo>().AsNoTracking().WhereMultipleApp(session?.User?.AppId).Where(wt => !wt.Deleted  && !wt.IsSimulation);
            var result = new PageResult<WorkTask>
            {
                Total = worktaskQuery.Count()
            };
            if (pageSize < 1)
                result.Items = worktaskQuery.Select(w => w.ToWorkTask()).ToList();
            else result.Items = worktaskQuery.OrderByDescending(w => w.CreationTime).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList().Select(w => w.ToWorkTask()).ToList();
            return await Task.FromResult(result);
        }


        private async Task<PageResult<StepWorkTask>> GetResultAsync(IQueryable<WorkStepInfo> workStepInfos, IQueryable<WorkTaskInfo> workTaskInfos, int pageIndex = 1, int pageSize = -1)
        {
            var maxStepIdQuery = from ws in workStepInfos
                                 orderby ws.CreationTime descending
                                 group ws by ws.WorkTaskId into g
                                 select new
                                 {
                                     Id = g.First().Id,
                                     WorkTaskId = g.Key
                                 };

            maxStepIdQuery = maxStepIdQuery.Distinct();


            var taskIds = maxStepIdQuery.Select(w => w.WorkTaskId);

            var query = workTaskInfos.Where(wt=>taskIds.Contains(wt.Id));



            var result = new PageResult<StepWorkTask>
            {
                Total = query.Count()
            };
            if (pageSize > 0)
            {
                query = query.OrderByDescending(wt => wt.CreationTime).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }

            var items = query.ToList().OrderByDescending(wt=>wt.CreationTime);

            var workTaskIds = items.Select(i => i.Id);
            var workStepIds = maxStepIdQuery.Where(i => workTaskIds.Contains(i.WorkTaskId)).Select(i=>i.Id).ToList();


            var worktaskQuery = workflowDbContext.Set<WorkTaskInfo>().Where(wt => workTaskIds.Contains(wt.Id)).ToList();
            var workstepQuery = workflowDbContext.Set<WorkStepInfo>().Where(ws => workStepIds.Contains(ws.Id)).ToList();


            result.Items = items.Select(i => new StepWorkTask
            {
                Step = workstepQuery.FirstOrDefault(s => s.WorkTaskId == i.Id)?.ToWorkStep(),
                Task = worktaskQuery.FirstOrDefault(s => s.Id == i.Id)?.ToWorkTask(),
            }).ToList();

            return await Task.FromResult(result);
        }
    }
    public class StepWorkTaskQuery
    {
        public Guid TaskId { get; set; }
        public Guid StepId { get; set; }
        public DateTime CreationTIme { get; set; }
    }
}
